package com.simple.dsrouter.strategy.impl;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.simple.dsrouter.config.DataSourceConfig;
import com.simple.dsrouter.config.TableConfig;
import com.simple.dsrouter.exception.DataSourceRouteException;
import com.simple.dsrouter.util.BeanPropertyAccessUtil;
import com.simple.dsrouter.util.StringUtil;

/**
 * 实现单库分表策略
 */
public class TableNameRouteStrategy extends AbstractRouteStrategy {

	@Override
	public void executeRoute(Object target, Method method, Object[] args) {
		Object parameterObj = args[0];
		Map parametersMap = new HashMap();
		if (parameterObj instanceof Map) {
			parametersMap = (Map) parameterObj;
		} else {
			parametersMap = BeanPropertyAccessUtil.transBean2Map(parameterObj);
		}
		TableBean tableBean = getPartionTableBean(parametersMap);
		if (tableBean == null) {
			throw new DataSourceRouteException("table config must not be null");
		}
		String physicalTableName = getPartionTableNameByModValue(tableBean);
		BeanPropertyAccessUtil.rewriteTableName(parameterObj, tableBean.getTableName(), physicalTableName);
	}

	private TableBean getPartionTableBean(Map parametersMap) {
		// 单库分表只有一个数据源
		List<DataSourceConfig> dataSources = dataSourceKeyMap.get(0);
		DataSourceConfig dataSource = dataSources.get(0);
		List<TableConfig> tables = dataSource.getTables();
		TableBean tableBean = null;
		if (tables != null && tables.size() > 0) {
			for (TableConfig table : tables) {
				if (parametersMap.containsKey(table.getTableField())) {
					if (StringUtil.isNullOrEmpty(table.getTablePrefix()) 
							|| StringUtil.isNullOrEmpty(table.getTableName()) 
							|| table.getTableNum() <= 0) {
						throw new DataSourceRouteException("tableField and tablePrefix must not be null and tableNum must be bigger than zero");
					}
					Object value = parametersMap.get(table.getTableField());
					if (value == null) {
						throw new DataSourceRouteException("routing parameter value must not be null");
					}
					long tableFieldValue = 0;
					try {
						tableFieldValue = Long.parseLong(value.toString());
					} catch (NumberFormatException e) {
						throw new DataSourceRouteException("routing parameter type only support: long(Long),int(Integer),short(Short),byte(Byte) type.");
					}
					tableBean = new TableBean();
					tableBean.setTablePrefix(table.getTablePrefix());
					tableBean.setTableName(table.getTableName());
					tableBean.setTableNum(table.getTableNum());
					tableBean.setTableFieldValue(tableFieldValue);
					break;
				}
			}
		}
		return tableBean;
	}

	private String getPartionTableNameByModValue(TableBean tableBean) {
		long routingIdentify = tableBean.getTableFieldValue();
		if (routingIdentify < 0) {
			routingIdentify = Math.abs(routingIdentify);
		}
		int modKey = 0;
		if (routingIdentify != 0) {
			modKey = (int) (routingIdentify % tableBean.getTableNum());
		}
		return tableBean.getTablePrefix() + modKey;
	}

	class TableBean extends TableConfig {

		private long tableFieldValue;

		public long getTableFieldValue() {
			return tableFieldValue;
		}

		public void setTableFieldValue(long tableFieldValue) {
			this.tableFieldValue = tableFieldValue;
		}
	}
}
